﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="XamlrPackage.cs" company="Xamlr">
//   The MIT License (MIT)
//   
//   Copyright (c) 2014 Brian Tyler
//   
//   Permission is hereby granted, free of charge, to any person obtaining a copy
//   of this software and associated documentation files (the "Software"), to deal
//   in the Software without restriction, including without limitation the rights
//   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//   copies of the Software, and to permit persons to whom the Software is
//   furnished to do so, subject to the following conditions:
//   
//   The above copyright notice and this permission notice shall be included in
//   all copies or substantial portions of the Software.
//   
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//   THE SOFTWARE.
// </copyright>
// <summary>
//   Defines the XamlrPackage type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Xamlr.Package
{
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    using EnvDTE;

    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Shell.Interop;

    /// <summary>
    /// The XAML Enaml package.
    /// </summary>
    [PackageRegistration(UseManagedResourcesOnly = true)]
    [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
    [ProvideOptionPage(typeof(ToolsOptions), "Xamlr", "General", 0, 0, true)]
    [Guid(Guids.PackageString)]
    [ProvideAutoLoad(UIContextGuids80.SolutionExists)]
    public sealed class XamlrPackage : Package
    {
        /// <summary>
        /// The Visual Studio 2K Command GUID.
        /// </summary>
        private static readonly string VsStd2KCmdIdGuid = typeof(VSConstants.VSStd2KCmdID).GUID.ToString("B");

        /// <summary>
        /// The Visual Studio 97 Command GUID.
        /// </summary>
        private static readonly string VSStd97CmdIdGuid = typeof(VSConstants.VSStd97CmdID).GUID.ToString("B");

        /// <summary>
        /// The <see cref="FormatDocumentCommand"/> factory.
        /// </summary>
        private readonly Func<FormatDocumentCommand> formatDocumentCommandFactory;

        /// <summary>
        /// The development environment.
        /// </summary>
        private DTE dte;

        /// <summary>
        /// The format document event.
        /// </summary>
        private CommandEvents formatDocumentEvent;

        /// <summary>
        /// The save item event.
        /// </summary>
        private CommandEvents saveProjectItemEvent;

        /// <summary>
        /// The save solution event.
        /// </summary>
        private CommandEvents saveSolutionEvent;

        /// <summary>
        /// Initializes a new instance of the <see cref="XamlrPackage"/> class. 
        /// </summary>
        public XamlrPackage()
        {
            Debug.WriteLine("Entering constructor for: {0}", this);
            this.formatDocumentCommandFactory = () => new FormatDocumentCommand(this.dte);
        }

        /// <summary>
        /// Gets the tools options.
        /// </summary>
        private ToolsOptions ToolsOptions
        {
            get
            {
                return (ToolsOptions)this.GetDialogPage(typeof(ToolsOptions)).AutomationObject;
            }
        }

        /// <summary>
        /// Performs package level initialization.
        /// </summary>
        protected override void Initialize()
        {
            Debug.WriteLine("Entering Initialize() of: {0}", this);
            base.Initialize();

            this.dte = this.GetService(typeof(DTE)) as DTE;

            if (this.dte == null)
            {
                throw new InvalidOperationException("DTE is null");
            }

            this.formatDocumentEvent = this.dte.Events.CommandEvents[VsStd2KCmdIdGuid, (int)VSConstants.VSStd2KCmdID.FORMATDOCUMENT];
            this.saveProjectItemEvent = this.dte.Events.CommandEvents[VSStd97CmdIdGuid, (int)VSConstants.VSStd97CmdID.SaveProjectItem];
            this.saveSolutionEvent = this.dte.Events.CommandEvents[VSStd97CmdIdGuid, (int)VSConstants.VSStd97CmdID.SaveSolution];
            
            this.formatDocumentEvent.BeforeExecute += this.OnFormatDocumentBeforeExecute;
            this.saveProjectItemEvent.BeforeExecute += this.OnSaveProjectItemBeforeExecute;
            this.saveSolutionEvent.BeforeExecute += this.OnSaveSolutionBeforeExecute;
        }

        /// <summary>
        /// Handles the Format Document 
        /// <seealso cref="CommandEvents.BeforeExecute"/>
        /// event.
        /// </summary>
        /// <param name="guid">
        /// The GUID that identifies the command family.
        /// </param>
        /// <param name="id">
        /// The ID that identifies the command.
        /// </param>
        /// <param name="customIn">
        /// The custom input parameters.
        /// </param>
        /// <param name="customOut">
        /// The custom output parameters.
        /// </param>
        /// <param name="cancelDefault">
        /// A value indicating whether the command has been cancelled.
        /// </param>
        private void OnFormatDocumentBeforeExecute(
            string guid, int id, object customIn, object customOut, ref bool cancelDefault)
        {
            Debug.WriteLine("Entering OnFormatDocumentBeforeExecute() of: {0}", this);
            if (!this.ToolsOptions.Enabled)
            {
                Debug.WriteLine("Xamlr is disabled, exiting");
                return;
            }

            var command = this.formatDocumentCommandFactory();
            if (command.CanExecute(this.dte.ActiveDocument))
            {
                command.Execute(this.dte.ActiveDocument);
                cancelDefault = true;
            }
        }

        /// <summary>
        /// Handles the Save Document 
        /// <seealso cref="CommandEvents.BeforeExecute"/>
        /// event.
        /// </summary>
        /// <param name="guid">
        /// The GUID that identifies the command family.
        /// </param>
        /// <param name="id">
        /// The ID that identifies the command.
        /// </param>
        /// <param name="customIn">
        /// The custom input parameters.
        /// </param>
        /// <param name="customOut">
        /// The custom output parameters.
        /// </param>
        /// <param name="cancelDefault">
        /// A value indicating whether the command has been cancelled.
        /// </param>
        private void OnSaveProjectItemBeforeExecute(
            string guid, int id, object customIn, object customOut, ref bool cancelDefault)
        {
            Debug.WriteLine("Entering OnFormatDocumentBeforeExecute() of: {0}", this);
            if (!this.ToolsOptions.Enabled || !this.ToolsOptions.FormatOnSave)
            {
                Debug.WriteLine("Xamlr is disabled, exiting");
                return;
            }

            var command = this.formatDocumentCommandFactory();
            if (command.CanExecute(this.dte.ActiveDocument))
            {
                command.Execute(this.dte.ActiveDocument);
            }
        }

        /// <summary>
        /// Handles the Save Document 
        /// <seealso cref="CommandEvents.BeforeExecute"/>
        /// event.
        /// </summary>
        /// <param name="guid">
        /// The GUID that identifies the command family.
        /// </param>
        /// <param name="id">
        /// The ID that identifies the command.
        /// </param>
        /// <param name="customIn">
        /// The custom input parameters.
        /// </param>
        /// <param name="customOut">
        /// The custom output parameters.
        /// </param>
        /// <param name="cancelDefault">
        /// A value indicating whether the command has been cancelled.
        /// </param>
        private void OnSaveSolutionBeforeExecute(
            string guid, int id, object customIn, object customOut, ref bool cancelDefault)
        {
            Debug.WriteLine("Entering OnFormatDocumentBeforeExecute() of: {0}", this);
            if (!this.ToolsOptions.Enabled || !this.ToolsOptions.FormatOnSave)
            {
                Debug.WriteLine("Xamlr is disabled, exiting");
                return;
            }

            foreach (Document document in this.dte.Documents)
            {
                var command = this.formatDocumentCommandFactory();
                if (command.CanExecute(document))
                {
                    command.Execute(document);
                }
            }
        }
    }
}
